package com.todo.biz.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.todo.biz.application.handler.linstener.event.CounterEvent;
import com.todo.biz.application.handler.linstener.message.CounterMessage;
import com.todo.common.common.entity.request.PageRequest;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.enums.BusinessSceneEnum;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.biz.common.enums.AssociateRelationTypeEnum;
import com.todo.biz.common.enums.CounterTypeEnum;
import com.todo.biz.infrastructure.entity.condition.AssociateCondition;
import com.todo.biz.infrastructure.entity.po.BizAssociatePO;
import com.todo.biz.infrastructure.repository.BizAssociateRepository;
import com.todo.biz.application.convert.BizBusinessConvert;
import com.todo.biz.application.service.BizAssociateService;
import com.todo.biz.application.entity.bo.BizAssociateBO;
import com.todo.common.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (BizAssociate)表服务实现类
 * TODO 注：当前都为mysql存储，后续如果起量需要依赖缓存，存储数据大致可以参考二进制形势（110，101，111，分别代表不同状态下的点赞，收藏，浏览）
 *
 * @author zhangwenxiang
 * @since 2024-03-04 00:19:41
 */
@Slf4j
@Service("bizAssociateService")
public class BizAssociateServiceImpl implements BizAssociateService {

    @Resource
    private BizAssociateRepository bizAssociateRepository;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;


    @Override
    public Boolean insertBizAssociate(BizAssociateBO bizAssociateBO) {
        if (bizAssociateBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (!bizAssociateBO.baseCheck()) {
            log.error("BizAssociateService#insertBizAssociate 新增业务关联失败，核心字段缺失 bizAssociateBO：【{}】", JSONObject.toJSONString(bizAssociateBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "核心字段缺失");
        }
        List<BizAssociateBO> bizAssociateBOS = queryBizAssociateByBizIdAndScene(bizAssociateBO.getUserId(), bizAssociateBO.getRelationId(), bizAssociateBO.getBusinessScene());
        if (CollectionUtils.isNotEmpty(bizAssociateBOS)) {
            for (BizAssociateBO alreadyData : bizAssociateBOS) {
                if (alreadyData.getRelationType().equals(bizAssociateBO.getRelationType())) {
                    //重复操作下删除数据
                    Boolean removeResult = bizAssociateRepository.removeBizAssociatePOById(alreadyData.getId());
                    return removeResult;
                }
            }
        }
        BizAssociatePO bizAssociatePO = BizBusinessConvert.converToBizAssociatePO(bizAssociateBO);
        Boolean insertResult = bizAssociateRepository.insertBizAssociatePO(bizAssociatePO);
        if (insertResult) {
            CounterMessage counterMessage = new CounterMessage();
            counterMessage.setBusinessScene(bizAssociateBO.getBusinessScene());
            counterMessage.setPlus(1);
            counterMessage.setCounterType(convertToCounterType(bizAssociateBO.getRelationType()));
            counterMessage.setBusinessId(bizAssociateBO.getRelationId());
            counterMessage.setUserId(bizAssociateBO.getUserId());
            applicationEventPublisher.publishEvent(new CounterEvent(counterMessage));
        }
        return insertResult;
    }

    @Override
    public Boolean removeBizAssociateById(Long userId, Long id) {
        if (id == null || id < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        BizAssociateBO bizAssociateBO = queryBizAssociateById(id);
        if (bizAssociateBO == null) {
            return true;
        }
        if (!bizAssociateBO.getUserId().equals(userId)) {
            log.error("BizAssociateService#removeBizAssociateById 根据主键删除失败，用户id不匹配 userId：【{}】，关联主键：【{}】", userId, id);
            return false;
        }
        Boolean removeResult = bizAssociateRepository.removeBizAssociatePOById(id);
        if (removeResult) {
            CounterMessage counterMessage = new CounterMessage();
            counterMessage.setBusinessScene(bizAssociateBO.getBusinessScene());
            counterMessage.setPlus(-1);
            counterMessage.setCounterType(convertToCounterType(bizAssociateBO.getRelationType()));
            counterMessage.setBusinessId(bizAssociateBO.getRelationId());
            counterMessage.setUserId(bizAssociateBO.getUserId());
            applicationEventPublisher.publishEvent(new CounterEvent(counterMessage));
        }
        return removeResult;
    }

    @Override
    public BizAssociateBO queryBizAssociateById(Long id) {
        if (id == null || id < 0) {
            return null;
        }
        BizAssociatePO bizAssociatePO = bizAssociateRepository.queryBizAssociatePOById(id);
        return BizBusinessConvert.convertToBizAssociateBO(bizAssociatePO);
    }

    @Override
    public List<BizAssociateBO> queryBizAssociateByBizIdAndScene(Long userId, Long bizId, BusinessSceneEnum scene) {
        if (userId == null || bizId == null || scene == null) {
            return Collections.emptyList();
        }
        List<BizAssociatePO> bizAssociatePOList = bizAssociateRepository.queryBizAssociateByBizIdAndScene(userId, bizId, scene);
        if (CollectionUtils.isEmpty(bizAssociatePOList)) {
            return Collections.emptyList();
        }
        return bizAssociatePOList.stream().map(BizBusinessConvert::convertToBizAssociateBO).collect(Collectors.toList());
    }

    @Override
    public PageResult<BizAssociateBO> queryBizAssociateByPage(Long userId, BusinessSceneEnum scene, AssociateRelationTypeEnum relationType, PageRequest pageRequest) {
        if (userId == null || scene == null || relationType == null || pageRequest == null) {
            return new PageResult<>();
        }
        AssociateCondition condition = new AssociateCondition();
        condition.setUserId(userId);
        condition.setBusinessScene(scene.getScene());
        condition.setRelationType(relationType.getType());
        condition.setPageIndex(pageRequest.getPageIndex());
        condition.setPageSize(pageRequest.getPageSize());
        condition.setCurrentIndex(pageRequest.getCurrentIndex());
        PageResult<BizAssociatePO> pageResult = bizAssociateRepository.queryBizAssociateByCondition(condition);
        if (pageResult == null) {
            return new PageResult<>();
        }
        PageResult<BizAssociateBO> result = new PageResult<>();
        result.setResults(pageResult.getResults() == null ? null : pageResult.getResults().stream().map(BizBusinessConvert::convertToBizAssociateBO).collect(Collectors.toList()));
        result.setPageNum(pageResult.getPageNum());
        result.setPageSize(pageResult.getPageSize());
        result.setTotal(pageResult.getTotal());
        result.setCurrentIndex(pageResult.getCurrentIndex());
        result.setHasNext(pageResult.isHasNext());
        return result;
    }

    @Override
    public Boolean removeBizAssociateByIdList(Long userId, List<Long> idList) {
        if (userId == null || CollectionUtils.isEmpty(idList)) {
            return false;
        }
        //TODO 由于当前删除模式下需要针对计数操作，单个删除已经实现，暂时循环调用单个情况
        for (Long id : idList) {
            removeBizAssociateById(userId, id);
        }
        return true;
    }


    private CounterTypeEnum convertToCounterType(AssociateRelationTypeEnum relationType) {
        if (relationType == null) {
            return null;
        }
        if (relationType.equals(AssociateRelationTypeEnum.COLLECT)) {
            return CounterTypeEnum.COLLECT;
        } else if (relationType.equals(AssociateRelationTypeEnum.LIKE)) {
            return CounterTypeEnum.LIKE;
        } else if (relationType.equals(AssociateRelationTypeEnum.BROWSE)) {
            return CounterTypeEnum.BROWSE;
        }
        return null;
    }
}
